package Logic;

import java.awt.Container;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import GUI.GameScreen;
import GUI.Panels.MainMenu;
import GameObjects.InstanceObject;
import GameObjects.Ships.Ship;
import GameObjects.Ships.Weapon.Bullets.Bullet;
import TestObjects.TestAlienShip;

public class Game implements ActionListener 
{	
	public static int ENVIROMENT_WIDTH = 1000;
	
	//The game environment and binary tree 
//	private QuadTree environment = new QuadTree();
	
	//Panels that will switch in out inside the Applet container
	//GamePanel is the actual game rendering
	private final GameScreen gamePanel = new GameScreen();
	//Main menu is the main menu...obviously
	private final MainMenu maninMenu = new MainMenu();
	
	private final Container container;
	
	private ArrayList<Ship> playerShips = new ArrayList<Ship>(); 
	private ArrayList<Ship> enemyShips = new ArrayList<Ship>();
	
	private ArrayList<Bullet> bullets = new ArrayList<Bullet>();
	private ArrayList<Bullet> enemyBullets = new ArrayList<Bullet>(); 
	
	private InstanceObject selectedObject = null;
	
	public Game(Container container)
	{
		//this here is a stub for testing for now
		TestAlienShip testShip = new TestAlienShip(100, 100, 0);
		playerShips.add(testShip);
		//add new ships here and that and the rest of the logic is taken care of
		//most of it is...
		testShip = new TestAlienShip(500, 100, 180);
		enemyShips.add(testShip);
		//end testing stub
		
		this.container = container;
		container.add(gamePanel);
		
		gamePanel.addMouseListener(new MouseListener() {
		
			@Override
			public void mouseReleased(MouseEvent e) {
				// TODO Auto-generated method stub
		
			}
		
			@Override
			public void mousePressed(MouseEvent e) {
				// TODO Auto-generated method stub
				int x = e.getX();
				int y = e.getY();		
				System.out.println(x+" "+y);
				clicked(e);
			}
		
			@Override
			public void mouseExited(MouseEvent e) {
				// TODO Auto-generated method stub
		
			}
		
			@Override
			public void mouseEntered(MouseEvent e) {
				// TODO Auto-generated method stub
		
			}
		
			@Override
			public void mouseClicked(MouseEvent e) {
				// TODO Auto-generated method stub
			}
		});
		
		gamePanel.addKeyListener(new KeyListener() {
		
			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub
		
			}
		
			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
				System.out.println(e.getKeyChar());
				keyUp(e);
			}
		
			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub
				System.out.println(e.getKeyChar());
				keyDown(e);
			}
		});
		
		gamePanel.requestFocusInWindow();
	}
	
	public void run()
	{
		while(true)
		{
			long start = System.nanoTime();
			tick();
	//		generateBadGuys();
			checkCollisions();
			render();
			gamePanel.repaint();
			long delay = calculateElapsedTimeMillis(start);
			if(delay < GameTime.DELAY_TIME){
				try{Thread.sleep(GameTime.DELAY_TIME-delay);}catch(Exception e){}
			}
			else 
				System.out.println("Delay time: "+delay);
		}
	}
	
	private long calculateElapsedTimeMillis(long beginTime) 
	{
        // Convert to ms, as beginTime is in ns
        return (System.nanoTime() - beginTime) / 1000000;
     }
	
	private void tick()
	{
		for(int i = 0; i < bullets.size(); i++)
		{
			if(bullets.get(i).tickObject())
				bullets.remove(i--);
		}
		
		for(int i = 0; i < enemyBullets.size(); i++)
		{
			if(enemyBullets.get(i).tickObject())
				enemyBullets.remove(i--);
		}
		
		for(Ship ship : playerShips)
		{
			ship.tickObject();
			bullets.addAll(ship.shoot());
		}
		
		for(Ship ship : enemyShips)
		{
			ship.tickObject();
			enemyBullets.addAll(ship.shoot());
		}
	}
	
	private void checkCollisions()
	{
		/**
		 * Will be split into differnt square bounds across the map
		 * Details in Google Document about how it is to be
		 * implemented fully.
		 * 
		 * For now is just a simple loop that checks everything...terrible but temporary
		 */
		for(Ship ship : playerShips)	
			for(Bullet bullet : enemyBullets)
				ship.hasCollided(bullet);
		
		for(Ship ship : enemyShips)	
			for(Bullet bullet : bullets)
				ship.hasCollided(bullet);
	}
	
	private void render()
	{
		int size = playerShips.size() + enemyShips.size() + bullets.size() + enemyBullets.size();
		ArrayList<InstanceObject> objects = new ArrayList<InstanceObject>(size);
		objects.addAll(playerShips);
		objects.addAll(bullets);
		objects.addAll(enemyShips);
		objects.addAll(enemyBullets);
		this.gamePanel.render(objects);
	}
	
	/**
	 * These methods need to be moved later on but for now they will reside here
	 */
	public void clicked(MouseEvent e)
	{
		int x = e.getX();
		int y = e.getY();		
		Point clicked = new Point(x, y);
		
		gamePanel.removeObjectPanels();
		
		/**
		 * Need to redo this a bit so that Panels can be added across all three bottom panels
		 */
		for(InstanceObject obj : playerShips)
			if((selectedObject = obj.hasClicked(clicked)) != null)//sexy call
			{
				//sending the panel to the object would be better, that way it can add whatever it wants
				//in fact that is what i shall do
				//gamePanel.addObjectPanelBottomRight(selectedObject.getPanel(this, GameScreen.BOTTOM_HEIGHT, GameScreen.BOTTOM_WIDTH));
				
				//this will be the new call when i get around to sorting it out
				selectedObject.setPanel(this, gamePanel.getBottomPanel());
				break;
			}
	}
	
	public void keyDown(KeyEvent e)
	{
//		char key = e.getKeyChar();
		int code = e.getKeyCode();
		if(this.selectedObject == null)
			return;
		else if(this.selectedObject instanceof Ship)
			keyResponseToShip(code, true);
	}
	
	public void keyUp(KeyEvent e)
	{
//		char key = e.getKeyChar();
		int code = e.getKeyCode();
		if(this.selectedObject == null)
			return;
		else if(this.selectedObject instanceof Ship)
			keyResponseToShip(code, false);
	}
	
	private void keyResponseToShip(int code, boolean down)
	{
		Ship ship = (Ship)this.selectedObject;
		System.out.println(code);
		switch(code)
		{
			case 87: //w
				ship.moveForward(down);
				break;
			case 65: //a
				ship.turnLeft(down);
				break;
			case 83: //s
				ship.moveBackwards(down);
				break;
			case 68: //d
				ship.turnRight(down);
				break;
			case 32: //space bar				
				break;
			default:
				break;
		}
	}
	
	public void actionEvent()
	{
		
	}

	@Override
	public void actionPerformed(ActionEvent e) 
	{
		System.out.println(e.getActionCommand());
	}
}
